﻿// Partial Copyright (c) LogoUI Software Solutions LTD
// Autor: Vladislav Spivak
// This source file is the part of LogoFX Framework http://logofx.codeplex.com
// See accompanying licences and credits.

using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;

namespace System.Collections
{
    public static class Extensions
    {
        public static int IndexOf(this ICollectionView collectionView,object obj)
        {
            return collectionView.OfType<object>().ToList().IndexOf(obj);
        }
		
        public static object GetItemAt(this ICollectionView collectionView,int index)
        {
            return collectionView.OfType<object>().ToList()[index];
        }

        /// <summary>
        /// Beautifies the string.
        /// </summary>
        /// <param name="originalName">original string.</param>
        /// <returns></returns>
        public static string Beautify(this IEnumerable<char> originalName)
        {
            StringBuilder word = new StringBuilder();
            List<string> words = new List<string>();
            foreach (char c in originalName)
            {
                // ignore punctuations and blanks
                if (Char.IsLetterOrDigit(c))
                {
                    if (Char.IsUpper(c))
                    {
                        if (word.Length > 0 && Char.IsLower(word[word.Length - 1]))
                        {
                            words.Add(word.ToString());
                            word = new StringBuilder();
                        }
                    }
                    word.Append(c);
                }
            }
            if (word.Length > 0)
                words.Add(word.ToString());
            String beautifiedName = String.Join(" ", words.ToArray());
            return beautifiedName;
        }

        /// <summary>
        /// Returns the first element of the sequence, or a default value if
        /// the sequence contains mo elements.
        /// </summary>
        /// <param name="source"></param>
        /// <exception cref="ArgumentNullException"></exception>
        /// <returns></returns>
        public static object FirstOrDefault(this IEnumerable source)
        {
            if (source == null)
                throw new ArgumentNullException("source");

            IEnumerator enumerator = source.GetEnumerator();
            enumerator.Reset();
            return enumerator.MoveNext() ? enumerator.Current : null;
        }

        /// <summary>
        /// Same as apply
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="ie">The ie.</param>
        /// <param name="action">The action.</param>
        public static void ForEach<T>(this IEnumerable<T> ie, Action<T> action)
        {
            ie.Apply(action);
        }



        /// <summary>
        /// Gets the number of items.
        /// </summary>
        /// <param name="ie"></param>
        /// <returns>The number of items.</returns>
        public static int Count(this IEnumerable ie)
        {
            return Enumerable.Count(ie.Cast<object>());
        }

        /// <summary>
        ///  Performs the specified action on each element of the <see cref="IEnumerable{T}"/> 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="ie"></param>
        /// <param name="action">The <see cref="System.Action()"/> delegate to perform on each element of the <see cref="IEnumerable{T}"/>.</param>
        /// <exception cref="System.ArgumentNullException">action is <see langword="null"/>.</exception>
        public static IEnumerable<T> Apply<T>(this IEnumerable<T> ie, Action<T> action)
        {
            foreach (T e in ie)
            {
                action(e);
            }
			return ie;
        }

        public static void TryApply<T>(this IEnumerable<T> ie, Action<T> action,Action<Exception> handler = null)
        {
            Action<Exception> local = handler ?? (a => Debug.WriteLine("Exception:{0}", a.Message));
            foreach (T e in ie)
            {

                try
                {
                    action(e);
                }
                catch (Exception exception)
                {
                    handler(exception);
                }
            }
        }

        /// <summary>
        /// <see cref="IEnumerable"/> implementation of Apply
        /// </summary>
        /// <param name="ie"></param>
        /// <param name="action"></param>
        public static IEnumerable Apply(this IEnumerable ie, Action<object> action)
        {
            Apply(ie.Cast<object>(), action);
            return ie;
        }

       //todo:be carefull, stack overflow
        public static IEnumerable<T> Traverse<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> fnRecurse)
        {
           //IEnumerable<T> result =
           // source.Concat(source.SelectMany(fnRecurse).Traverse(fnRecurse));
           //return result;
           foreach (T item in source)
           {
              yield return item;

              IEnumerable<T> seqRecurse = fnRecurse(item);

              if (seqRecurse != null)
              {
                 foreach (T itemRecurse in Traverse(seqRecurse, fnRecurse))
                 {
                    yield return itemRecurse;
                 }
              }
           }
        }
    }
}
